package com.csw.android.dev_utils.utils

import android.app.Activity
import android.app.Application
import android.os.Bundle
import androidx.lifecycle.MutableLiveData
import com.csw.android.dev_utils.handler.MainHandler
import java.lang.ref.WeakReference
import java.util.LinkedList

object AppUtils {
    private val mainHandler = MainHandler()

    /**
     * 当前app对象
     */
    var application: Application? = null

    /**
     * 已创建的activity集合
     */
    var createdActivities = LinkedList<WeakReference<Activity>>()

    /**
     * 已可见的Activity集合
     */
    var startedActivities = LinkedList<WeakReference<Activity>>()

    /**
     * 前台Activity列表，发现一种特殊情况，转场动画居然会在新的Activity进入onResume后，上个Activity会短暂onResume
     * 再OnPause，导致可能同时存在两个处于onResume状态的Activity....
     */
    var resumedActivities = LinkedList<WeakReference<Activity>>()

    /**
     * 前台Activity
     */
    val resumedActivity: WeakReference<Activity>?
        get() = resumedActivities.lastOrNull()

    /**
     * app是否处于前台
     */
    val appInForeground = MutableLiveData(false)

    /**
     * app是否处于可见
     */
    val appInVisible = MutableLiveData(false)

    fun init(application: Application) {
        if (this.application != null) {
            return
        }
        this.application = application
        application.registerActivityLifecycleCallbacks(object :
            Application.ActivityLifecycleCallbacks {

            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
                createdActivities.add(WeakReference(activity))
            }

            override fun onActivityStarted(activity: Activity) {
                startedActivities.add(WeakReference(activity))
                updateVisible(true)
            }

            override fun onActivityResumed(activity: Activity) {
                resumedActivities.add(WeakReference(activity))
                updateForeground(true)
            }

            override fun onActivityPaused(activity: Activity) {
                resumedActivities.iterator().run {
                    while (hasNext()) {
                        if (next().get() == activity) {
                            remove()
                        }
                    }
                }
                checkForeground()
            }

            override fun onActivityStopped(activity: Activity) {
                removeActivityFromList(startedActivities, activity)
                updateVisible(startedActivities.isNotEmpty())
            }

            override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}

            override fun onActivityDestroyed(activity: Activity) {
                removeActivityFromList(createdActivities, activity)
            }

        })
    }

    private fun updateVisible(visible: Boolean) {
        if (appInVisible.value == visible) {
            return
        }
        appInVisible.value = visible
        logAppState()
    }

    private fun updateForeground(foreground: Boolean) {
        if (appInForeground.value == foreground) {
            return
        }
        appInForeground.value = foreground
        logAppState()
    }

    private fun checkForeground() {
        //onPause
        mainHandler.post {
            //after this code，nextActivity start enter foreground:create->start->resume，check the
            // nextActivity is our app's.
            mainHandler.post {
                updateForeground(resumedActivity?.get() != null)
            }
        }
    }

    private fun logAppState() {
//        LogUtils.v(this@AppUtils, toString())
    }

    private fun removeActivityFromList(
        activities: LinkedList<WeakReference<Activity>>,
        activity: Activity
    ) {
        activities.iterator().run {
            while (hasNext()) {
                if (next().get() == activity) {
                    remove()
                    break
                }
            }
        }
    }

    override fun toString(): String {
        val stringBuffer = StringBuffer()
        stringBuffer.appendLine("AppUtils{")
        stringBuffer.appendLine("   package = ${application?.packageName}")
        stringBuffer.appendLine("   appInVisible = ${appInVisible.value}")
        stringBuffer.appendLine("   appInForeground = ${appInForeground.value}")
        stringBuffer.appendLine("   createdActivities[")
        createdActivities.forEach {
            it.get()?.run {
                stringBuffer.appendLine("       ${javaClass.simpleName},(${hashCode()})")
            }
        }
        stringBuffer.appendLine("   ]")
        stringBuffer.appendLine("   startedActivities[")
        startedActivities.forEach {
            it.get()?.run {
                stringBuffer.appendLine("       ${javaClass.simpleName},(${hashCode()})")
            }
        }
        stringBuffer.appendLine("   ]")
        val ra = resumedActivity?.get()
        if (ra != null) {
            stringBuffer.appendLine("   resumedActivity =  ${ra.javaClass.simpleName},(${ra.hashCode()})")
        } else {
            stringBuffer.appendLine("   resumedActivity =  null")
        }
        stringBuffer.appendLine("}")
        return stringBuffer.toString()
    }

}